package schedule

import (
	"encoding/json"
	"errors"
	"log"
	"log/slog"
	"raymond/api/bnb"
	"raymond/global"
	"raymond/model"
	"raymond/util"
	"strings"
	"time"
)

func ListenBEP20Recharge() {
	contractList := bnb.GetBep20ContractList()
	bnbContractWallets := model.ListContractWallet(global.BNB)
	if bnbContractWallets == nil || len(*bnbContractWallets) == 0 || contractList == nil || len(contractList) == 0 {
		return
	}
	cwMap := make(map[string][]model.BSNContractWallet)
	var addrs []string
	for _, bcw := range *bnbContractWallets {
		contract := strings.ToLower(bcw.Contract)
		cwMap[contract] = append(cwMap[contract], bcw)
		addrs = append(addrs, bcw.Addr)
	}
	for _, contract := range contractList {
		var bsnTxList []model.BNBTransactionJournal
		for _, wallet := range cwMap[contract] {
			resp, err := bnb.ListenBSCBEP20(contract, wallet.Addr)
			if err != nil {
				slog.Error("listen BSC BEP20", "error", err)
				continue
			}
			if len(resp.Result) <= 0 {
				continue
			}
			txList := model.AllBNBTxList()
			hashList := make([]string, len(*txList))
			for i, tx := range *txList {
				hashList[i] = tx.Hash
			}

			for _, tx := range resp.Result {
				if util.InStrings(tx.Hash, &hashList) {
					continue
				}
				if strings.EqualFold(tx.From, tx.To) {
					continue
				}
				if !util.InStrings(tx.To, &addrs) {
					continue
				}
				dbBsnTx := &model.BNBTransactionJournal{
					BlockNumber:       tx.BlockNumber,
					TimeStamp:         tx.TimeStamp,
					Hash:              tx.Hash,
					Nonce:             tx.Nonce,
					BlockHash:         tx.BlockHash,
					FromAddr:          tx.From,
					ContractAddress:   tx.ContractAddress,
					ToAddr:            tx.To,
					Value:             tx.Value,
					TokenName:         tx.TokenName,
					TokenSymbol:       tx.TokenSymbol,
					TokenDecimal:      tx.TokenDecimal,
					TransactionIndex:  tx.TransactionIndex,
					Gas:               tx.Gas,
					GasPrice:          tx.GasPrice,
					GasUsed:           tx.GasUsed,
					CumulativeGasUsed: tx.CumulativeGasUsed,
					InputParams:       tx.Input,
					Confirmations:     tx.Confirmations,
				}
				err := rechargeBEP20(tx.From, tx.To, tx.Value, tx.ContractAddress)
				if err != nil {
					slog.Error("rechargeBEP20", "error", err)
					continue
				}
				bsnTxList = append(bsnTxList, *dbBsnTx)
			}
		}
		exists := make(map[string]bool)
		journalSet := make([]model.BNBTransactionJournal, 0)
		for _, tx := range bsnTxList {
			lowerHash := strings.ToLower(tx.Hash)
			if _, ok := exists[lowerHash]; !ok {
				exists[lowerHash] = true
				journalSet = append(journalSet, tx)
			}
		}
		if len(journalSet) > 0 {
			err := model.BatchInsertBNBTxJournal(&journalSet)
			if err != nil {
				slog.Error("save txJournal err", err)
			}
		}
	}
}

type recharge_request struct {
	CryptoCurrency string `json:"cryptoCurrency"`
	ContractAddr   string `json:"contractAddr"`
	Amount         string `json:"amount"`
	From           string `json:"from"`
	To             string `json:"to"`
	OrderTime      int64  `json:"orderTime"`
}

type recharge_response struct {
	Success       string `json:"success"`
	Message       string `json:"message"`
	DetailMessage string `json:"detailMessage"`
	Code          uint64 `json:"code"`
	Data          string `json:"data"`
	Uri           string `json:"uri"`
	Method        string `json:"method"`
	Timestamp     string `json:"timestamp"`
}

func rechargeBEP20(from string, to string, value string, contract string) error {
	now := time.Now().Unix()
	req := recharge_request{
		CryptoCurrency: string(global.BCPCBEP20),
		ContractAddr:   contract,
		Amount:         value,
		From:           from,
		To:             to,
		OrderTime:      now,
	}
	req_bytes, _ := json.Marshal(req)
	url := global.GetAppAddr() + "/wallet/app/order/recharge"
	resp_bytes, err := global.HttpPost(url, req_bytes)
	if err != nil {
		log.Println("recharge", "error", err)
		return err
	}
	var resp recharge_response
	json.Unmarshal(resp_bytes, &resp)
	if resp.Code != 200 {
		return errors.New(resp.DetailMessage)
	}
	return nil
}
